/*******************************************************************************
 * Copyright (c) 2013 Callista Enterprise AB - Björn Beskow
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * Based on m2e-cxf-codegen-connector
 * (https://code.google.com/a/eclipselabs.org/p/m2e-cxf-codegen-connector/)
 *******************************************************************************/
package com.googlecode.m2e.connectors.cxf;

import java.io.File;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Set;

import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.MojoExecution;
import org.codehaus.plexus.util.Scanner;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.m2e.core.MavenPlugin;
import org.eclipse.m2e.core.embedder.IMaven;
import org.eclipse.m2e.core.project.configurator.MojoExecutionBuildParticipant;
import org.sonatype.plexus.build.incremental.BuildContext;
  
public class CxfXjcBuildParticipant extends MojoExecutionBuildParticipant
{
  
    public CxfXjcBuildParticipant( MojoExecution execution )
    {
        super( execution, true );
    }

	@Override
    public Set<IProject> build( int kind, IProgressMonitor monitor ) throws Exception
    {
  
        final IMaven maven = MavenPlugin.getMaven();
        final BuildContext buildContext = getBuildContext();
        final MavenSession mavenSession = getSession();
        final MojoExecution mojoExecution = getMojoExecution();
  
        File sourceRoot = maven.getMojoParameterValue( mavenSession, mojoExecution, "sourceRoot",
                                                       File.class );
  
     // check if any of the schema or binding files have changed
        boolean filesModified = false;
  
        if ( sourceRoot != null && ( !sourceRoot.exists() || 
        		IncrementalProjectBuilder.CLEAN_BUILD == kind || IncrementalProjectBuilder.FULL_BUILD == kind ) )
        {
            filesModified = true;
        }
        else
        {
  
            final List<?> xsdOptions = maven.getMojoParameterValue( mavenSession, mojoExecution,
                                                                  "xsdOptions", List.class );
  
            // getMojoParameterValue returns an instance of xsdOptions from a different classloader, so casting doesn't work.
            for ( Object obj : xsdOptions )
            {
                Class<? extends Object> k = obj.getClass();
                Method getXsd = k.getMethod( "getXsd" );
                Method getBindingFile = k.getMethod( "getBindingFile" );
  
                String xsd = getXsd.invoke( obj ).toString();
  
                filesModified = ( !isEmpty( xsd ) && !isEmpty( getModifiedFiles( buildContext, new File( xsd ) ) ) );
  
                if ( !filesModified )
                {
                	String bindingFile = (String) getBindingFile.invoke( obj );
                    filesModified = ( !isEmpty( bindingFile ) &&
                                      !isEmpty( getModifiedFiles( buildContext, new File( bindingFile ) ) ) );
                }
  
                if ( filesModified )
                {
                    break;
                }
            }
  
        }
  
        // If no changes, simply return
        if ( !filesModified )
        {
            return null;
        }
  
        // Otherwise, execute mojo
        final Set<IProject> result = super.build( kind, monitor );
  
        if ( sourceRoot != null )
        {
        	// tell m2e builder to refresh generated files
            buildContext.refresh( sourceRoot );
        }
  
        return result;
    }
	
	static <T> boolean isEmpty( final T[] array )
	{
		return array == null || array.length == 0;
	}
   
	static boolean isEmpty(String str) {
        return (str == null || str.length() == 0);
    }
	
    static String[] getModifiedFiles( BuildContext buildContext, File source )
        throws Exception
    {
        if ( buildContext == null || source == null || !source.exists() )
        {
            return null;
        }
  
        final Scanner ds = buildContext.newScanner( source );
  
        ds.scan();
  
        return ds.getIncludedFiles();
    }
}